package org.e_gold.factory.crawler;

import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.e_gold.dao.CountryDAO;
import org.e_gold.dao.LeagueDAO;
import org.e_gold.model.crawler.livescore.CEvent;
import org.e_gold.model.crawler.livescore.Country;
import org.e_gold.model.crawler.livescore.League;
import org.e_gold.service.CEventService;
import org.e_gold.service.CountryService;
import org.e_gold.service.LeagueService;
import org.e_gold.util.Bet365;
import org.e_gold.util.Constant;
import org.e_gold.util.StringUtil;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * @author Thang Nguyen
 */
@Component
@Scope("singleton")
public class Bet365CrawlerThread extends Thread implements Bet365, Constant {

	private static final Logger	logger			= Logger.getLogger(Bet365CrawlerThread.class);

	@Autowired
	private CountryDAO			countryDAO;

	@Autowired
	private CountryService		countryService;

	@Autowired
	private LeagueDAO			leagueDAO;

	@Autowired
	private LeagueService		leagueService;

	@Autowired
	private CEventService		cEventService;

	private final int			SLEEP_SECOND	= 60 * 60 * 1000;

	private Map<String, String> headers;
	private Map<String, String> cookieMap = new HashMap<String, String>();
	private Connection connection;
	private final String UNKNOW_COUNTRY = "WORLD";

	public void initAndStart(){
		cookieMap = prepareBasicCookie();
		headers = prepareBasicHeaders(); 
		headers.put(COOKIE, getCookie());
		this.start();
	}

	@Override
	public void run() {
		try {
			while (true) {
				try {
					logger.info("++++++++++++Bet  Crwaler has started++++++++++++ ");
					exposeSite();
					logger.info("++++++++++++Bet  Crwaler has done++++++++++++ ");
					logger.info("++++++++++++Bet  Crwaler sleep ["+ (SLEEP_SECOND/60/1000) + "] minutes++++++++++++ ");
					Thread.sleep(SLEEP_SECOND);
				} catch (Exception ex) {
					logger.info("Internet problem???: " + ex.getMessage());
					logger.error(ex);
					ex.printStackTrace();
				}
			}
		} catch (Exception ex) {
			logger.info("++++++++++++Live Score Crwaler has stopped++++++++++++ "
					+ ex.getMessage());
			logger.error(ex);
			ex.printStackTrace();
		}
	}

	//	private class Crawler extends Thread{
	//
	//		@Override
	//		public void run() {
	//			try {
	//				while (true) {
	//					try {
	//						logger.info("++++++++++++Bet  Crwaler has started++++++++++++ ");
	//						exposeSite();
	//						logger.info("++++++++++++Bet  Crwaler has done++++++++++++ ");
	//						logger.info("++++++++++++Bet  Crwaler sleep ["+ (SLEEP_SECOND/60/1000) + "] minutes++++++++++++ ");
	//						Thread.sleep(SLEEP_SECOND);
	//					} catch (Exception ex) {
	//						logger.info("Internet problem???: " + ex.getMessage());
	//						logger.error(ex);
	//						ex.printStackTrace();
	//					}
	//				}
	//			} catch (Exception ex) {
	//				logger.info("++++++++++++Live Score Crwaler has stopped++++++++++++ "
	//						+ ex.getMessage());
	//				logger.error(ex);
	//				ex.printStackTrace();
	//			}
	//		}
	//	}

	public void exposeSite() throws Exception{
		try {
			Document doc = redirectNavigator(FULL_TIME_PAGE);

			Element mainList = doc.getElementById("subMenu_2");
			logger.info("++++Bet Crwaler..exporting...");
			if (mainList != null) {
				Elements countryList = mainList.getElementsByClass("Level2");
				logger.info("++++<Bet Crwaler..found: " + (countryList.size() - 1));
				for(int i = 1; i < countryList.size(); i++){
					exposeCountryList(countryList.get(i));
				}
			}
		} catch (Exception ex) {
			logger.info("Error parsing: " + ex);
			ex.printStackTrace();
		}
	}

	private void exposeCountryList(Element eCountry) throws Exception{
		try{
			Country country = null;
			String countryName = eCountry.text();
			String href = eCountry.select("a").attr("href");
			String fullUrl = StringUtil.buildUrl(BASE_FULL_TIME_SOCCER, href);
			boolean coupon = false;

			//prepare URL
			if(href.startsWith("../")){
				country = new Country(UNKNOW_COUNTRY, "");
				coupon = true;
			}else{
				country = new Country(countryName, fullUrl);
			}

			//get the country
			country = countryService.getCountryPersisted(country);

			//crawling
			if(!coupon){
				exposeCountry(fullUrl, country);
			}else{
				League league = leagueService.getLeaguePersisted(new League(countryName, country));
				exposeLeague(fullUrl, league);
			}
		}catch(Exception ex){
			logger.info("Error when parsing country list: " + eCountry.text());
			ex.printStackTrace();
		}
	}

	private void exposeCountry(String href, Country country){
		try{
			Document doc = redirectNavigator(href);
			Element mainList = doc.getElementById("subMenu_2");
			if (mainList != null) {
				Elements leagueList = mainList.getElementsByClass("Level2");
				logger.info("++++<Bet Crwaler..found [" + country.getName() + "]: " + (leagueList.size() - 1));
				//System.out.println("\\" + country.getName());
				for(int i = 1; i < leagueList.size(); i++){
					Element league = leagueList.get(i);
					String leagueName = league.select("a").text();
					String leagueHref = StringUtil.buildUrl(href, league.select("a").attr("href"));
					League l = leagueService.getLeaguePersisted(new League(leagueName, country));

					//System.out.println("\t" + l.getName());
					exposeLeague(leagueHref, l);
					//System.out.println("\t--------------");
				}
			}
		}catch(Exception ex){
			logger.info("Error when parsing country of: " + country.getName() + "++ at: " + href);
			ex.printStackTrace();
		}
	}

	private void exposeLeague(String href, League league){
		try{
			Document doc = redirectNavigator(href);
			Element table = doc.select("div.Coupon").first();
			Elements events = table.getElementsByTag("th");
			for (int i = 0; i < events.size(); i++) {
				Element event = events.get(i);
				String[] keos = event.text().split(" v ");
				CEvent cEvent = new CEvent(keos[0], keos[1]);
				cEvent.setLeague(league);
				cEventService.insert(cEvent);
				//System.out.println("\t\t" + event.text());
			}
		}catch(Exception ex){
			logger.info("Error when parsing league of: " + league.getName() + "++ at: " + href);
			ex.printStackTrace();
		}
	}

	private Map<String, String> prepareBasicHeaders() {

		Map<String, String> basicHeader = new HashMap<String, String>();
		basicHeader.put(ACCEPT, ACCEPT_DATA);
		basicHeader.put(ACCEPT_ENCODING, ACCEPT_ENCODING_DATA);
		basicHeader.put(ACCEPT_LANGUAGE, ACCEPT_LANGUAGE_DATA);
		basicHeader.put(CONNECTION, CONNECTION_DATA);
		basicHeader.put(HOST, HOST_DATA);
		basicHeader.put(USER_AGENT, USER_AGENT_DATA);
		basicHeader.put(CACHE_CONTROL, CACHE_CONTROL_DATA);
		basicHeader.put(PRAGMA, PRAGMA_DATA);
		return basicHeader;
	}

	private Map<String, String> prepareBasicCookie(){
		Map<String, String> basicCookie = new HashMap<String, String>();
		basicCookie.put("session", "processform=0");
		basicCookie.put("0", "processform=0");
		basicCookie.put("usdi", "uqid=4127F1B0-39F0-4D6E-86EC-7DF8B59BFFDB");
		basicCookie.put("aps03", "lng=1&tzi=26&ct=204&cst=0&cg=0");
		basicCookie.put("pstk", "4F8C4F63B105455A9C0C62AB52C6BE2D000003");
		basicCookie.put("lng", "1");

		return basicCookie;
	}

	private Connection navigator(String url) {

		Connection connection = Jsoup.connect(url);
		for (Map.Entry<String, String> entry : headers.entrySet()) {
			connection.header(entry.getKey(), entry.getValue());
		}
		connection.cookies(cookieMap);
		connection.header(COOKIE, getCookie());

		connection.followRedirects(false);
		return connection;
	}

	private String getCookie() {

		String cookie = "";
		for (Map.Entry<String, String> entry : cookieMap.entrySet()) {
			cookie += ";" + entry.getKey() + "=" + entry.getValue();
		}
		if (!StringUtils.isEmpty(cookie))
		{
			return cookie.substring(1);
		}
		return "";
	}

	private Document redirectNavigator(String url) throws Exception {

		Document doc = null;
		try {
			connection = navigator(url).timeout(30000);
			doc = connection.get();
			while (responseCode(connection) == HttpStatus.FOUND.value()) {
				String redirectLocation = connection.response().header(LOCATION);

				Map<String, String> responseCookie = connection.response().cookies();
				for(Map.Entry<String, String> entry: responseCookie.entrySet()){
					cookieMap.put(entry.getKey(), entry.getValue());
				}
				connection = navigator(redirectLocation);
				doc = connection.get();
			}
		} catch (Exception e) {
			logger.error("redirectNavigator error : " + url);
			throw e;
		}

		return doc;
	}

	public int responseCode(Connection connection) {
		return connection.response().statusCode();
	}

	public static void main(String[] args) {
		Bet365CrawlerThread lThread = new Bet365CrawlerThread();
		lThread.initAndStart();
	}
}
